/*
 * libwebsockets - small server side websockets and web server implementation
 *
 * Copyright (C) 2010 Andy Green <andy@warmcat.com>
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation:
 *  version 2.1 of the License.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 *  MA  02110-1301  USA
 */

#include <openssl/sha.h>
#include "private-libwebsockets.h"
#ifdef __cplusplus
extern "C" {
	#include <cstddef>
#endif
		const struct lws_tokens lws_tokens[WSI_TOKEN_COUNT] = {

			/* win32 can't do C99 */

		/*	[WSI_TOKEN_GET_URI]	=	*/{ "GET ",			 4 },
		/*	[WSI_TOKEN_HOST]	=	*/{ "Host:",			 5 },
		/*	[WSI_TOKEN_CONNECTION]	=	*/{ "Connection:",		11 },
		/*	[WSI_TOKEN_KEY1]	=	*/{ "Sec-WebSocket-Key1:",	19 },
		/*	[WSI_TOKEN_KEY2]	=	*/{ "Sec-WebSocket-Key2:",	19 },
		/*	[WSI_TOKEN_PROTOCOL]	=	*/{ "Sec-WebSocket-Protocol:",	23 },
		/*	[WSI_TOKEN_UPGRADE]	=	*/{ "Upgrade:",			 8 },
		/*	[WSI_TOKEN_ORIGIN]	=	*/{ "Origin:",			 7 },
		/*	[WSI_TOKEN_DRAFT]	=	*/{ "Sec-WebSocket-Draft:",	20 },
		/*	[WSI_TOKEN_CHALLENGE]	=	*/{ "\x0d\x0a",			 2 },

		/*	[WSI_TOKEN_KEY]		=	*/{ "Sec-WebSocket-Key:",	18 },
		/*	[WSI_TOKEN_VERSION]	=	*/{ "Sec-WebSocket-Version:",	22 },
		/*	[WSI_TOKEN_SWORIGIN]=		*/{ "Sec-WebSocket-Origin:",	21 },

		/*	[WSI_TOKEN_EXTENSIONS]	=	*/{ "Sec-WebSocket-Extensions:", 25 },

		/*	[WSI_TOKEN_ACCEPT]	=	*/{ "Sec-WebSocket-Accept:",	21 },
		/*	[WSI_TOKEN_NONCE]	=	*/{ "Sec-WebSocket-Nonce:",	20 },
		/*	[WSI_TOKEN_HTTP]	=	*/{ "HTTP/1.1 ",		 9 },
		/*	[WSI_TOKEN_MUXURL]	=	*/{ "",		 -1 },

		};

		int libwebsocket_parse(struct libwebsocket *wsi, unsigned char c)
		{
			int n;

			switch (wsi->parser_state) {
			case WSI_TOKEN_GET_URI:
			case WSI_TOKEN_HOST:
			case WSI_TOKEN_CONNECTION:
			case WSI_TOKEN_KEY1:
			case WSI_TOKEN_KEY2:
			case WSI_TOKEN_PROTOCOL:
			case WSI_TOKEN_UPGRADE:
			case WSI_TOKEN_ORIGIN:
			case WSI_TOKEN_SWORIGIN:
			case WSI_TOKEN_DRAFT:
			case WSI_TOKEN_CHALLENGE:
			case WSI_TOKEN_KEY:
			case WSI_TOKEN_VERSION:
			case WSI_TOKEN_ACCEPT:
			case WSI_TOKEN_NONCE:
			case WSI_TOKEN_EXTENSIONS:
			case WSI_TOKEN_HTTP:
			case WSI_TOKEN_MUXURL:

				debug("WSI_TOKEN_(%d) '%c'\n", wsi->parser_state, c);

				/* collect into malloc'd buffers */
				/* optional space swallow */
				if (!wsi->utf8_token[wsi->parser_state].token_len && c == ' ')
					break;

				/* special case space terminator for get-uri */
				if (wsi->parser_state == WSI_TOKEN_GET_URI && c == ' ') {
					wsi->utf8_token[wsi->parser_state].token[
					   wsi->utf8_token[wsi->parser_state].token_len] = '\0';
					wsi->parser_state = WSI_TOKEN_SKIPPING;
					break;
				}

				/* allocate appropriate memory */
				if (wsi->utf8_token[wsi->parser_state].token_len ==
								   wsi->current_alloc_len - 1) {
					/* need to extend */
					wsi->current_alloc_len += LWS_ADDITIONAL_HDR_ALLOC;
					if (wsi->current_alloc_len >= LWS_MAX_HEADER_LEN) {
						/* it's waaay to much payload, fail it */
						strcpy(wsi->utf8_token[wsi->parser_state].token,
						   "!!! Length exceeded maximum supported !!!");
						wsi->parser_state = WSI_TOKEN_SKIPPING;
						break;
					}
					wsi->utf8_token[wsi->parser_state].token =
						   (char *) realloc(wsi->utf8_token[wsi->parser_state].token,
									wsi->current_alloc_len);
				}

				/* bail at EOL */
				if (wsi->parser_state != WSI_TOKEN_CHALLENGE && c == '\x0d') {
					wsi->utf8_token[wsi->parser_state].token[
					   wsi->utf8_token[wsi->parser_state].token_len] = '\0';
					wsi->parser_state = WSI_TOKEN_SKIPPING_SAW_CR;
					debug("*\n");
					break;
				}

				wsi->utf8_token[wsi->parser_state].token[
						wsi->utf8_token[wsi->parser_state].token_len++] = c;

				/* per-protocol end of headers management */

				if (wsi->parser_state != WSI_TOKEN_CHALLENGE)
					break;

				/* -76 has no version header ... server */
				if (!wsi->utf8_token[WSI_TOKEN_VERSION].token_len &&
				   wsi->mode != LWS_CONNMODE_WS_CLIENT_WAITING_SERVER_REPLY &&
						  wsi->utf8_token[wsi->parser_state].token_len != 8)
					break;

				/* -76 has no version header ... client */
				if (!wsi->utf8_token[WSI_TOKEN_VERSION].token_len &&
				   wsi->mode == LWS_CONNMODE_WS_CLIENT_WAITING_SERVER_REPLY &&
					wsi->utf8_token[wsi->parser_state].token_len != 16)
					break;

				/* <= 03 has old handshake with version header needs 8 bytes */
				if (wsi->utf8_token[WSI_TOKEN_VERSION].token_len &&
					 atoi(wsi->utf8_token[WSI_TOKEN_VERSION].token) < 4 &&
						  wsi->utf8_token[wsi->parser_state].token_len != 8)
					break;

				/* no payload challenge in 01 + */

				if (wsi->utf8_token[WSI_TOKEN_VERSION].token_len &&
					   atoi(wsi->utf8_token[WSI_TOKEN_VERSION].token) > 0) {
					wsi->utf8_token[WSI_TOKEN_CHALLENGE].token_len = 0;
					free(wsi->utf8_token[WSI_TOKEN_CHALLENGE].token);
					wsi->utf8_token[WSI_TOKEN_CHALLENGE].token = NULL;
				}

				/* For any supported protocol we have enough payload */

				debug("Setting WSI_PARSING_COMPLETE\n");
				wsi->parser_state = WSI_PARSING_COMPLETE;
				break;

			case WSI_INIT_TOKEN_MUXURL:
				wsi->parser_state = WSI_TOKEN_MUXURL;
				wsi->current_alloc_len = LWS_INITIAL_HDR_ALLOC;

				wsi->utf8_token[wsi->parser_state].token =
						(char *) malloc(wsi->current_alloc_len);
				wsi->utf8_token[wsi->parser_state].token_len = 0;
				break;

				/* collecting and checking a name part */
			case WSI_TOKEN_NAME_PART:
				debug("WSI_TOKEN_NAME_PART '%c'\n", c);

				if (wsi->name_buffer_pos == sizeof(wsi->name_buffer) - 1) {
					/* name bigger than we can handle, skip until next */
					wsi->parser_state = WSI_TOKEN_SKIPPING;
					break;
				}
				wsi->name_buffer[wsi->name_buffer_pos++] = c;
				wsi->name_buffer[wsi->name_buffer_pos] = '\0';

				for (n = 0; n < WSI_TOKEN_COUNT; n++) {
					if (wsi->name_buffer_pos != lws_tokens[n].token_len)
						continue;
					if (strcasecmp(lws_tokens[n].token, wsi->name_buffer))
						continue;
					debug("known hdr '%s'\n", wsi->name_buffer);

					/*
					 * WSORIGIN is protocol equiv to ORIGIN,
					 * JWebSocket likes to send it, map to ORIGIN
					 */
					if (n == WSI_TOKEN_SWORIGIN)
						n = WSI_TOKEN_ORIGIN;

					wsi->parser_state = (enum lws_token_indexes) (WSI_TOKEN_GET_URI + n);

					n = WSI_TOKEN_COUNT;

					/*  If the header has been seen already, just append */
					if (wsi->utf8_token[wsi->parser_state].token)
						continue;

					wsi->current_alloc_len = LWS_INITIAL_HDR_ALLOC;
					wsi->utf8_token[wsi->parser_state].token =
							(char *) malloc(wsi->current_alloc_len);
					wsi->utf8_token[wsi->parser_state].token_len = 0;
				}

				/* colon delimiter means we just don't know this name */

				if (wsi->parser_state == WSI_TOKEN_NAME_PART && c == ':') {
					debug("skipping unknown header '%s'\n",
										  wsi->name_buffer);
					wsi->parser_state = WSI_TOKEN_SKIPPING;
					break;
				}

				if (wsi->parser_state != WSI_TOKEN_CHALLENGE)
					break;

				/* don't look for payload when it can just be http headers */

				if (!wsi->utf8_token[WSI_TOKEN_UPGRADE].token_len) {
					/* they're HTTP headers, not websocket upgrade! */
					debug("Setting WSI_PARSING_COMPLETE "
									 "from http headers\n");
					wsi->parser_state = WSI_PARSING_COMPLETE;
				}

				/* 04 version has no packet content after end of hdrs */

				if (wsi->utf8_token[WSI_TOKEN_VERSION].token_len &&
					 atoi(wsi->utf8_token[WSI_TOKEN_VERSION].token) >= 4) {
					debug("04 header completed\n");
					wsi->parser_state = WSI_PARSING_COMPLETE;
					wsi->utf8_token[WSI_TOKEN_CHALLENGE].token_len = 0;
					free(wsi->utf8_token[WSI_TOKEN_CHALLENGE].token);
					wsi->utf8_token[WSI_TOKEN_CHALLENGE].token = NULL;
				}

				/* client parser? */

				if (wsi->ietf_spec_revision >= 4) {
					debug("04 header completed\n");
					wsi->parser_state = WSI_PARSING_COMPLETE;
				}

				break;

				/* skipping arg part of a name we didn't recognize */
			case WSI_TOKEN_SKIPPING:
				debug("WSI_TOKEN_SKIPPING '%c'\n", c);
				if (c == '\x0d')
					wsi->parser_state = WSI_TOKEN_SKIPPING_SAW_CR;
				break;
			case WSI_TOKEN_SKIPPING_SAW_CR:
				debug("WSI_TOKEN_SKIPPING_SAW_CR '%c'\n", c);
				if (c == '\x0a')
					wsi->parser_state = WSI_TOKEN_NAME_PART;
				else
					wsi->parser_state = WSI_TOKEN_SKIPPING;
				wsi->name_buffer_pos = 0;
				break;
				/* we're done, ignore anything else */
			case WSI_PARSING_COMPLETE:
				debug("WSI_PARSING_COMPLETE '%c'\n", c);
				break;

			default:	/* keep gcc happy */
				break;
			}

			return 0;
		}

		unsigned char
		xor_no_mask(struct libwebsocket *wsi, unsigned char c)
		{
			return c;
		}

		unsigned char
		xor_mask_04(struct libwebsocket *wsi, unsigned char c)
		{
			c ^= wsi->masking_key_04[wsi->frame_mask_index++];
			if (wsi->frame_mask_index == 20)
				wsi->frame_mask_index = 0;

			return c;
		}

		unsigned char
		xor_mask_05(struct libwebsocket *wsi, unsigned char c)
		{
			return c ^ wsi->frame_masking_nonce_04[(wsi->frame_mask_index++) & 3];
		}



		int
		libwebsocket_rx_sm(struct libwebsocket *wsi, unsigned char c)
		{
			int n;
			char buf[20 + 4];
			struct lws_tokens eff_buf;
			int handled;
			int m;

		#if 0
			fprintf(stderr, "RX: %02X ", c);
		#endif

			switch (wsi->lws_rx_parse_state) {
			case LWS_RXPS_NEW:

				switch (wsi->ietf_spec_revision) {
				/* Firefox 4.0b6 likes this as of 30 Oct 2010 */
				case 0:
					if (c == 0xff)
						wsi->lws_rx_parse_state = LWS_RXPS_SEEN_76_FF;
					if (c == 0) {
						wsi->lws_rx_parse_state =
									   LWS_RXPS_EAT_UNTIL_76_FF;
						wsi->rx_user_buffer_head = 0;
					}
					break;
				case 4:
				case 5:
				case 6:
					wsi->all_zero_nonce = 1;
					wsi->frame_masking_nonce_04[0] = c;
					if (c)
						wsi->all_zero_nonce = 0;
					wsi->lws_rx_parse_state = LWS_RXPS_04_MASK_NONCE_1;
					break;
				case 7:
				case 8:
				case 13:
					/*
					 * no prepended frame key any more
					 */
					wsi->all_zero_nonce = 1;
					goto handle_first;

				default:
					fprintf(stderr, "libwebsocket_rx_sm doesn't know "
						"about spec version %d\n", wsi->ietf_spec_revision);
					break;
				}
				break;
			case LWS_RXPS_04_MASK_NONCE_1:
				wsi->frame_masking_nonce_04[1] = c;
				if (c)
					wsi->all_zero_nonce = 0;
				wsi->lws_rx_parse_state = LWS_RXPS_04_MASK_NONCE_2;
				break;
			case LWS_RXPS_04_MASK_NONCE_2:
				wsi->frame_masking_nonce_04[2] = c;
				if (c)
					wsi->all_zero_nonce = 0;
				wsi->lws_rx_parse_state = LWS_RXPS_04_MASK_NONCE_3;
				break;
			case LWS_RXPS_04_MASK_NONCE_3:
				wsi->frame_masking_nonce_04[3] = c;
				if (c)
					wsi->all_zero_nonce = 0;

				if (wsi->protocol->owning_server->options &
							   LWS_SERVER_OPTION_DEFEAT_CLIENT_MASK)
					goto post_mask;

				if (wsi->ietf_spec_revision > 4)
					goto post_sha1;

				/*
				 * we are able to compute the frame key now
				 * it's a SHA1 of ( frame nonce we were just sent, concatenated
				 * with the connection masking key we computed at handshake
				 * time ) -- yeah every frame from the client invokes a SHA1
				 * for no real reason so much for lightweight.
				 */

				buf[0] = wsi->frame_masking_nonce_04[0];
				buf[1] = wsi->frame_masking_nonce_04[1];
				buf[2] = wsi->frame_masking_nonce_04[2];
				buf[3] = wsi->frame_masking_nonce_04[3];

				memcpy(buf + 4, wsi->masking_key_04, 20);

				/*
				 * wsi->frame_mask_04 will be our recirculating 20-byte XOR key
				 * for this frame
				 */

				SHA1((unsigned char *)buf, 4 + 20, wsi->frame_mask_04);

		post_sha1:

				/*
				 * start from the zero'th byte in the XOR key buffer since
				 * this is the start of a frame with a new key
				 */

				wsi->frame_mask_index = 0;

		post_mask:
				wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_1;
				break;

			/*
			 *  04 logical framing from the spec (all this is masked when incoming
			 *  and has to be unmasked)
			 *
			 * We ignore the possibility of extension data because we don't
			 * negotiate any extensions at the moment.
			 *
			 *    0                   1                   2                   3
			 *    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
			 *   +-+-+-+-+-------+-+-------------+-------------------------------+
			 *   |F|R|R|R| opcode|R| Payload len |    Extended payload length    |
			 *   |I|S|S|S|  (4)  |S|     (7)     |             (16/63)           |
			 *   |N|V|V|V|       |V|             |   (if payload len==126/127)   |
			 *   | |1|2|3|       |4|             |                               |
			 *   +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
			 *   |     Extended payload length continued, if payload len == 127  |
			 *   + - - - - - - - - - - - - - - - +-------------------------------+
			 *   |                               |         Extension data        |
			 *   +-------------------------------+ - - - - - - - - - - - - - - - +
			 *   :                                                               :
			 *   +---------------------------------------------------------------+
			 *   :                       Application data                        :
			 *   +---------------------------------------------------------------+
			 *
			 *  We pass payload through to userland as soon as we get it, ignoring
			 *  FIN.  It's up to userland to buffer it up if it wants to see a
			 *  whole unfragmented block of the original size (which may be up to
			 *  2^63 long!)
			 */

			case LWS_RXPS_04_FRAME_HDR_1:
		handle_first:

				/*
				 * 04 spec defines the opcode like this: (1, 2, and 3 are
				 * "control frame" opcodes which may not be fragmented or
				 * have size larger than 126)
				 *
				 *       frame-opcode           =
				 *	       %x0 ; continuation frame
				 *		/ %x1 ; connection close
				 *		/ %x2 ; ping
				 *		/ %x3 ; pong
				 *		/ %x4 ; text frame
				 *		/ %x5 ; binary frame
				 *		/ %x6-F ; reserved
				 *
				 *		FIN (b7)
				 */

				if (wsi->ietf_spec_revision < 7)
					c = wsi->xor_mask(wsi, c);

				if (c & 0x70)
					fprintf(stderr,
						"Frame has unknown extension bits set 1 %02X\n", c);

				/* translate all incoming opcodes into v7+ map */
				if (wsi->ietf_spec_revision < 7)
					switch (c & 0xf) {
					case LWS_WS_OPCODE_04__CONTINUATION:
						wsi->opcode = LWS_WS_OPCODE_07__CONTINUATION;
						break;
					case LWS_WS_OPCODE_04__CLOSE:
						wsi->opcode = LWS_WS_OPCODE_07__CLOSE;
						break;
					case LWS_WS_OPCODE_04__PING:
						wsi->opcode = LWS_WS_OPCODE_07__PING;
						break;
					case LWS_WS_OPCODE_04__PONG:
						wsi->opcode = LWS_WS_OPCODE_07__PONG;
						break;
					case LWS_WS_OPCODE_04__TEXT_FRAME:
						wsi->opcode = LWS_WS_OPCODE_07__TEXT_FRAME;
						break;
					case LWS_WS_OPCODE_04__BINARY_FRAME:
						wsi->opcode = LWS_WS_OPCODE_07__BINARY_FRAME;
						break;
					default:
						fprintf(stderr, "reserved opcodes not "
									"usable pre v7 protocol\n");
						return -1;
					}
				else
					wsi->opcode = c & 0xf;

				wsi->final = !!((c >> 7) & 1);

				wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN;
				break;

			case LWS_RXPS_04_FRAME_HDR_LEN:

				if (wsi->ietf_spec_revision < 7)
					c = wsi->xor_mask(wsi, c);

				if ((c & 0x80) && wsi->ietf_spec_revision < 7) {
					fprintf(stderr, "Frame has extensions "
									   "set illegally 2\n");
					/* kill the connection */
					return -1;
				}

				wsi->this_frame_masked = !!(c & 0x80);

				switch (c & 0x7f) {
				case 126:
					/* control frames are not allowed to have big lengths */
					if (wsi->opcode & 8)
						goto illegal_ctl_length;

					wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN16_2;
					break;
				case 127:
					/* control frames are not allowed to have big lengths */
					if (wsi->opcode & 8)
						goto illegal_ctl_length;

					wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_8;
					break;
				default:
					wsi->rx_packet_length = c & 0x7f;
					if (wsi->this_frame_masked)
						wsi->lws_rx_parse_state =
								LWS_RXPS_07_COLLECT_FRAME_KEY_1;
					else
						wsi->lws_rx_parse_state =
							LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;
					break;
				}
				break;

			case LWS_RXPS_04_FRAME_HDR_LEN16_2:
				if (wsi->ietf_spec_revision < 7)
					c = wsi->xor_mask(wsi, c);

				wsi->rx_packet_length = c << 8;
				wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN16_1;
				break;

			case LWS_RXPS_04_FRAME_HDR_LEN16_1:
				if (wsi->ietf_spec_revision < 7)
					c = wsi->xor_mask(wsi, c);

				wsi->rx_packet_length |= c;
				if (wsi->this_frame_masked)
					wsi->lws_rx_parse_state =
							LWS_RXPS_07_COLLECT_FRAME_KEY_1;
				else
					wsi->lws_rx_parse_state =
						LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;
				break;

			case LWS_RXPS_04_FRAME_HDR_LEN64_8:
				if (wsi->ietf_spec_revision < 7)
					c = wsi->xor_mask(wsi, c);
				if (c & 0x80) {
					fprintf(stderr, "b63 of length must be zero\n");
					/* kill the connection */
					return -1;
				}
		#if defined __LP64__
				wsi->rx_packet_length = ((size_t)c) << 56;
		#else
				wsi->rx_packet_length = 0;
		#endif
				wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_7;
				break;

			case LWS_RXPS_04_FRAME_HDR_LEN64_7:
				if (wsi->ietf_spec_revision < 7)
					c = wsi->xor_mask(wsi, c);
		#if defined __LP64__
				wsi->rx_packet_length |= ((size_t)c) << 48;
		#endif
				wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_6;
				break;

			case LWS_RXPS_04_FRAME_HDR_LEN64_6:
				if (wsi->ietf_spec_revision < 7)
					c = wsi->xor_mask(wsi, c);
		#if defined __LP64__
				wsi->rx_packet_length |= ((size_t)c) << 40;
		#endif
				wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_5;
				break;

			case LWS_RXPS_04_FRAME_HDR_LEN64_5:
				if (wsi->ietf_spec_revision < 7)
					c = wsi->xor_mask(wsi, c);
		#if defined __LP64__
				wsi->rx_packet_length |= ((size_t)c) << 32;
		#endif
				wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_4;
				break;

			case LWS_RXPS_04_FRAME_HDR_LEN64_4:
				if (wsi->ietf_spec_revision < 7)
					c = wsi->xor_mask(wsi, c);
				wsi->rx_packet_length |= ((size_t)c) << 24;
				wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_3;
				break;

			case LWS_RXPS_04_FRAME_HDR_LEN64_3:
				if (wsi->ietf_spec_revision < 7)
					c = wsi->xor_mask(wsi, c);
				wsi->rx_packet_length |= ((size_t)c) << 16;
				wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_2;
				break;

			case LWS_RXPS_04_FRAME_HDR_LEN64_2:
				if (wsi->ietf_spec_revision < 7)
					c = wsi->xor_mask(wsi, c);
				wsi->rx_packet_length |= ((size_t)c) << 8;
				wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_1;
				break;

			case LWS_RXPS_04_FRAME_HDR_LEN64_1:
				if (wsi->ietf_spec_revision < 7)
					c = wsi->xor_mask(wsi, c);
				wsi->rx_packet_length |= ((size_t)c);
				if (wsi->this_frame_masked)
					wsi->lws_rx_parse_state =
							LWS_RXPS_07_COLLECT_FRAME_KEY_1;
				else
					wsi->lws_rx_parse_state =
						LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;
				break;

			case LWS_RXPS_EAT_UNTIL_76_FF:
				if (c == 0xff) {
					wsi->lws_rx_parse_state = LWS_RXPS_NEW;
					goto issue;
				}
				wsi->rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING +
								  (wsi->rx_user_buffer_head++)] = c;

				if (wsi->rx_user_buffer_head != MAX_USER_RX_BUFFER)
					break;
		issue:
				if (wsi->protocol->callback)
					wsi->protocol->callback(wsi->protocol->owning_server,
					  wsi, LWS_CALLBACK_RECEIVE,
					  wsi->user_space,
					  &wsi->rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING],
					  wsi->rx_user_buffer_head);
				wsi->rx_user_buffer_head = 0;
				break;
			case LWS_RXPS_SEEN_76_FF:
				if (c)
					break;

				debug("Seen that client is requesting "
						"a v76 close, sending ack\n");
				buf[0] = 0xff;
				buf[1] = 0;
				n = libwebsocket_write(wsi, buf, 2, LWS_WRITE_HTTP);
				if (n < 0) {
					fprintf(stderr, "ERROR writing to socket");
					return -1;
				}
				debug("  v76 close ack sent, server closing skt\n");
				/* returning < 0 will get it closed in parent */
				return -1;

			case LWS_RXPS_PULLING_76_LENGTH:
				break;


			case LWS_RXPS_07_COLLECT_FRAME_KEY_1:
				wsi->frame_masking_nonce_04[0] = c;
				if (c)
					wsi->all_zero_nonce = 0;
				wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_2;
				break;

			case LWS_RXPS_07_COLLECT_FRAME_KEY_2:
				wsi->frame_masking_nonce_04[1] = c;
				if (c)
					wsi->all_zero_nonce = 0;
				wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_3;
				break;

			case LWS_RXPS_07_COLLECT_FRAME_KEY_3:
				wsi->frame_masking_nonce_04[2] = c;
				if (c)
					wsi->all_zero_nonce = 0;
				wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_4;
				break;

			case LWS_RXPS_07_COLLECT_FRAME_KEY_4:
				wsi->frame_masking_nonce_04[3] = c;
				if (c)
					wsi->all_zero_nonce = 0;
				wsi->lws_rx_parse_state =
							LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;
				wsi->frame_mask_index = 0;
				break;


			case LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED:
				if (wsi->ietf_spec_revision < 4 ||
					 (wsi->all_zero_nonce && wsi->ietf_spec_revision >= 5))
					wsi->rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING +
						   (wsi->rx_user_buffer_head++)] = c;
				else
					wsi->rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING +
						   (wsi->rx_user_buffer_head++)] =
									  wsi->xor_mask(wsi, c);

				if (--wsi->rx_packet_length == 0) {
					wsi->lws_rx_parse_state = LWS_RXPS_NEW;
					goto spill;
				}
				if (wsi->rx_user_buffer_head != MAX_USER_RX_BUFFER)
					break;
		spill:
				/*
				 * is this frame a control packet we should take care of at this
				 * layer?  If so service it and hide it from the user callback
				 */

				debug("spill on %s\n", wsi->protocol->name);

				switch (wsi->opcode) {
				case LWS_WS_OPCODE_07__CLOSE:
					/* is this an acknowledgement of our close? */
					if (wsi->state == WSI_STATE_AWAITING_CLOSE_ACK) {
						/*
						 * fine he has told us he is closing too, let's
						 * finish our close
						 */
						debug("seen client close ack\n");
						return -1;
					}
					debug("server sees client close packet\n");
					/* parrot the close packet payload back */
					n = libwebsocket_write(wsi, (char *)
					   &wsi->rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING],
							 wsi->rx_user_buffer_head, LWS_WRITE_CLOSE);
					wsi->state = WSI_STATE_RETURNED_CLOSE_ALREADY;
					/* close the connection */
					return -1;

				case LWS_WS_OPCODE_07__PING:
					/* parrot the ping packet payload back as a pong */
					n = libwebsocket_write(wsi, (char *)
						&wsi->rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING],
							wsi->rx_user_buffer_head, LWS_WRITE_PONG);
					/* ... then just drop it */
					wsi->rx_user_buffer_head = 0;
					return 0;

				case LWS_WS_OPCODE_07__PONG:
					/* keep the statistics... */
					wsi->pings_vs_pongs--;
					/* ... then just drop it */
					wsi->rx_user_buffer_head = 0;
					return 0;

				case LWS_WS_OPCODE_07__TEXT_FRAME:
				case LWS_WS_OPCODE_07__BINARY_FRAME:
					break;

				default:

					debug("passing opcode %x up to exts\n", wsi->opcode);

					/*
					 * It's something special we can't understand here.
					 * Pass the payload up to the extension's parsing
					 * state machine.
					 */

					eff_buf.token = &wsi->rx_user_buffer[
								   LWS_SEND_BUFFER_PRE_PADDING];
					eff_buf.token_len = wsi->rx_user_buffer_head;

					handled = 0;
					for (n = 0; n < wsi->count_active_extensions; n++) {
						m = wsi->active_extensions[n]->callback(
							wsi->protocol->owning_server,
							wsi->active_extensions[n], wsi,
							LWS_EXT_CALLBACK_EXTENDED_PAYLOAD_RX,
								wsi->active_extensions_user[n],
										   &eff_buf, 0);
						if (m)
							handled = 1;
					}

					if (!handled)
						fprintf(stderr, "Unhandled extended opcode "
							"0x%x - ignoring frame\n", wsi->opcode);

					wsi->rx_user_buffer_head = 0;
					return 0;
				}

				/*
				 * No it's real payload, pass it up to the user callback.
				 * It's nicely buffered with the pre-padding taken care of
				 * so it can be sent straight out again using libwebsocket_write
				 */

				wsi->rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING +
								   wsi->rx_user_buffer_head] = '\0';

				if (wsi->protocol->callback)
					wsi->protocol->callback(wsi->protocol->owning_server,
								wsi, LWS_CALLBACK_RECEIVE,
								wsi->user_space,
					  &wsi->rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING],
									  wsi->rx_user_buffer_head);
				else
					fprintf(stderr, "No callback on payload spill!\n");

				wsi->rx_user_buffer_head = 0;
				break;
			}

			return 0;

		illegal_ctl_length:

			fprintf(stderr, "Control frame asking for "
					"extended length is illegal\n");
			/* kill the connection */
			return -1;
		}


		int libwebsocket_client_rx_sm(struct libwebsocket *wsi, unsigned char c)
		{
			int n;
			char buf[20 + 4];
			int callback_action = LWS_CALLBACK_CLIENT_RECEIVE;
			int handled;
			struct lws_tokens eff_buf;
			int m;

			debug(" CRX: %02X %d\n", c, wsi->lws_rx_parse_state);

			switch (wsi->lws_rx_parse_state) {
			case LWS_RXPS_NEW:

				switch (wsi->ietf_spec_revision) {
				/* Firefox 4.0b6 likes this as of 30 Oct */
				case 0:
					if (c == 0xff)
						wsi->lws_rx_parse_state = LWS_RXPS_SEEN_76_FF;
					if (c == 0) {
						wsi->lws_rx_parse_state =
									   LWS_RXPS_EAT_UNTIL_76_FF;
						wsi->rx_user_buffer_head = 0;
					}
					break;
				case 4:
				case 5:
				case 6:
				case 7:
				case 8:
				case 13:
			/*
			 *  04 logical framing from the spec (all this is masked when
			 *  incoming and has to be unmasked)
			 *
			 * We ignore the possibility of extension data because we don't
			 * negotiate any extensions at the moment.
			 *
			 *    0                   1                   2                   3
			 *    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
			 *   +-+-+-+-+-------+-+-------------+-------------------------------+
			 *   |F|R|R|R| opcode|R| Payload len |    Extended payload length    |
			 *   |I|S|S|S|  (4)  |S|     (7)     |             (16/63)           |
			 *   |N|V|V|V|       |V|             |   (if payload len==126/127)   |
			 *   | |1|2|3|       |4|             |                               |
			 *   +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
			 *   |     Extended payload length continued, if payload len == 127  |
			 *   + - - - - - - - - - - - - - - - +-------------------------------+
			 *   |                               |         Extension data        |
			 *   +-------------------------------+ - - - - - - - - - - - - - - - +
			 *   :                                                               :
			 *   +---------------------------------------------------------------+
			 *   :                       Application data                        :
			 *   +---------------------------------------------------------------+
			 *
			 *  We pass payload through to userland as soon as we get it, ignoring
			 *  FIN.  It's up to userland to buffer it up if it wants to see a
			 *  whole unfragmented block of the original size (which may be up to
			 *  2^63 long!)
			 *
			 *  Notice in v7 RSV4 is set to indicate 32-bit frame key is coming in
			 *  after length, unlike extension data which is now deprecated, this
			 *  does not impact the payload length calculation.
			 */

				/*
				 * 04 spec defines the opcode like this: (1, 2, and 3 are
				 * "control frame" opcodes which may not be fragmented or
				 * have size larger than 126)
				 *
				 *       frame-opcode           =
				 *		  %x0 ; continuation frame
				 *		/ %x1 ; connection close
				 *		/ %x2 ; ping
				 *		/ %x3 ; pong
				 *		/ %x4 ; text frame
				 *		/ %x5 ; binary frame
				 *		/ %x6-F ; reserved
				 *
				 *		FIN (b7)
				 */

					if (c & 0x70)
						fprintf(stderr, "Frame has unknown extension "
							"bits set on first framing byte %02X\n", c);

					if (wsi->ietf_spec_revision < 7)
						switch (c & 0xf) {
						case LWS_WS_OPCODE_04__CONTINUATION:
							wsi->opcode =
								LWS_WS_OPCODE_07__CONTINUATION;
							break;
						case LWS_WS_OPCODE_04__CLOSE:
							wsi->opcode = LWS_WS_OPCODE_07__CLOSE;
							break;
						case LWS_WS_OPCODE_04__PING:
							wsi->opcode = LWS_WS_OPCODE_07__PING;
							break;
						case LWS_WS_OPCODE_04__PONG:
							wsi->opcode = LWS_WS_OPCODE_07__PONG;
							break;
						case LWS_WS_OPCODE_04__TEXT_FRAME:
							wsi->opcode =
								  LWS_WS_OPCODE_07__TEXT_FRAME;
							break;
						case LWS_WS_OPCODE_04__BINARY_FRAME:
							wsi->opcode =
								LWS_WS_OPCODE_07__BINARY_FRAME;
							break;
						default:
							fprintf(stderr, "reserved opcodes not "
								   "usable pre v7 protocol\n");
							return -1;
						}
					else
						wsi->opcode = c & 0xf;

					wsi->final = !!((c >> 7) & 1);

					wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN;
					break;

				default:
					fprintf(stderr, "client_rx_sm doesn't know how "
						"to handle spec version %02d\n",
									   wsi->ietf_spec_revision);
					break;
				}
				break;


			case LWS_RXPS_04_FRAME_HDR_LEN:

				if ((c & 0x80) && wsi->ietf_spec_revision < 7) {
					fprintf(stderr,
							  "Frame has extensions set illegally 4\n");
					/* kill the connection */
					return -1;
				}

				wsi->this_frame_masked = !!(c & 0x80);

				switch (c & 0x7f) {
				case 126:
					/* control frames are not allowed to have big lengths */
					if (wsi->opcode & 8)
						goto illegal_ctl_length;
					wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN16_2;
					break;
				case 127:
					/* control frames are not allowed to have big lengths */
					if (wsi->opcode & 8)
						goto illegal_ctl_length;
					wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_8;
					break;
				default:
					wsi->rx_packet_length = c;
					if (wsi->this_frame_masked)
						wsi->lws_rx_parse_state =
								LWS_RXPS_07_COLLECT_FRAME_KEY_1;
					else {
						if (c)
							wsi->lws_rx_parse_state =
							LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;
						else {
							wsi->lws_rx_parse_state = LWS_RXPS_NEW;
							goto spill;
						}
					}
					break;
				}
				break;

			case LWS_RXPS_04_FRAME_HDR_LEN16_2:
				wsi->rx_packet_length = c << 8;
				wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN16_1;
				break;

			case LWS_RXPS_04_FRAME_HDR_LEN16_1:
				wsi->rx_packet_length |= c;
				if (wsi->this_frame_masked)
					wsi->lws_rx_parse_state =
							LWS_RXPS_07_COLLECT_FRAME_KEY_1;
				else {
					if (wsi->rx_packet_length)
						wsi->lws_rx_parse_state =
							LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;
					else {
						wsi->lws_rx_parse_state = LWS_RXPS_NEW;
						goto spill;
					}
				}
				break;

			case LWS_RXPS_04_FRAME_HDR_LEN64_8:
				if (c & 0x80) {
					fprintf(stderr, "b63 of length must be zero\n");
					/* kill the connection */
					return -1;
				}
		#if defined __LP64__
				wsi->rx_packet_length = ((size_t)c) << 56;
		#else
				wsi->rx_packet_length = 0;
		#endif
				wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_7;
				break;

			case LWS_RXPS_04_FRAME_HDR_LEN64_7:
		#if defined __LP64__
				wsi->rx_packet_length |= ((size_t)c) << 48;
		#endif
				wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_6;
				break;

			case LWS_RXPS_04_FRAME_HDR_LEN64_6:
		#if defined __LP64__
				wsi->rx_packet_length |= ((size_t)c) << 40;
		#endif
				wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_5;
				break;

			case LWS_RXPS_04_FRAME_HDR_LEN64_5:
		#if defined __LP64__
				wsi->rx_packet_length |= ((size_t)c) << 32;
		#endif
				wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_4;
				break;

			case LWS_RXPS_04_FRAME_HDR_LEN64_4:
				wsi->rx_packet_length |= ((size_t)c) << 24;
				wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_3;
				break;

			case LWS_RXPS_04_FRAME_HDR_LEN64_3:
				wsi->rx_packet_length |= ((size_t)c) << 16;
				wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_2;
				break;

			case LWS_RXPS_04_FRAME_HDR_LEN64_2:
				wsi->rx_packet_length |= ((size_t)c) << 8;
				wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_1;
				break;

			case LWS_RXPS_04_FRAME_HDR_LEN64_1:
				wsi->rx_packet_length |= (size_t)c;
				if (wsi->this_frame_masked)
					wsi->lws_rx_parse_state =
							LWS_RXPS_07_COLLECT_FRAME_KEY_1;
				else {
					if (wsi->rx_packet_length)
						wsi->lws_rx_parse_state =
							LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;
					else {
						wsi->lws_rx_parse_state = LWS_RXPS_NEW;
						goto spill;
					}
				}
				break;

			case LWS_RXPS_07_COLLECT_FRAME_KEY_1:
				wsi->frame_masking_nonce_04[0] = c;
				if (c)
					wsi->all_zero_nonce = 0;
				wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_2;
				break;

			case LWS_RXPS_07_COLLECT_FRAME_KEY_2:
				wsi->frame_masking_nonce_04[1] = c;
				if (c)
					wsi->all_zero_nonce = 0;
				wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_3;
				break;

			case LWS_RXPS_07_COLLECT_FRAME_KEY_3:
				wsi->frame_masking_nonce_04[2] = c;
				if (c)
					wsi->all_zero_nonce = 0;
				wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_4;
				break;

			case LWS_RXPS_07_COLLECT_FRAME_KEY_4:
				wsi->frame_masking_nonce_04[3] = c;
				if (c)
					wsi->all_zero_nonce = 0;

				if (wsi->rx_packet_length)
					wsi->lws_rx_parse_state =
							LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;
				else {
					wsi->lws_rx_parse_state = LWS_RXPS_NEW;
					goto spill;
				}
				break;

			case LWS_RXPS_EAT_UNTIL_76_FF:
				if (c == 0xff) {
					wsi->lws_rx_parse_state = LWS_RXPS_NEW;
					goto issue;
				}
				wsi->rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING +
								  (wsi->rx_user_buffer_head++)] = c;

				if (wsi->rx_user_buffer_head != MAX_USER_RX_BUFFER)
					break;
		issue:
				if (wsi->protocol->callback)
					wsi->protocol->callback(wsi->protocol->owning_server,
								wsi,
								LWS_CALLBACK_CLIENT_RECEIVE,
								wsi->user_space,
					  &wsi->rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING],
									  wsi->rx_user_buffer_head);
				wsi->rx_user_buffer_head = 0;
				break;
			case LWS_RXPS_SEEN_76_FF:
				if (c)
					break;

				debug("Seen that client is requesting "
						"a v76 close, sending ack\n");
				buf[0] = 0xff;
				buf[1] = 0;
				n = libwebsocket_write(wsi, buf, 2, LWS_WRITE_HTTP);
				if (n < 0) {
					fprintf(stderr, "ERROR writing to socket");
					return -1;
				}
				debug("  v76 close ack sent, server closing skt\n");
				/* returning < 0 will get it closed in parent */
				return -1;

			case LWS_RXPS_PULLING_76_LENGTH:
				break;

			case LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED:
				if ((!wsi->this_frame_masked) || wsi->all_zero_nonce)
					wsi->rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING +
						   (wsi->rx_user_buffer_head++)] = c;
				else
					wsi->rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING +
						   (wsi->rx_user_buffer_head++)] =
									  wsi->xor_mask(wsi, c);

				if (--wsi->rx_packet_length == 0) {
					wsi->lws_rx_parse_state = LWS_RXPS_NEW;
					goto spill;
				}
				if (wsi->rx_user_buffer_head != MAX_USER_RX_BUFFER)
					break;
		spill:

				handled = 0;

				/*
				 * is this frame a control packet we should take care of at this
				 * layer?  If so service it and hide it from the user callback
				 */

				switch (wsi->opcode) {
				case LWS_WS_OPCODE_07__CLOSE:
					/* is this an acknowledgement of our close? */
					if (wsi->state == WSI_STATE_AWAITING_CLOSE_ACK) {
						/*
						 * fine he has told us he is closing too, let's
						 * finish our close
						 */
						debug("seen server's close ack\n");
						return -1;
					}
					debug("client sees server close packet len = %d\n", wsi->rx_user_buffer_head);
					/* parrot the close packet payload back */
					n = libwebsocket_write(wsi, (char *)
					   &wsi->rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING],
							 wsi->rx_user_buffer_head, LWS_WRITE_CLOSE);
					debug("client writing close ack returned %d\n", n);
					wsi->state = WSI_STATE_RETURNED_CLOSE_ALREADY;
					/* close the connection */
					return -1;

				case LWS_WS_OPCODE_07__PING:
					/* parrot the ping packet payload back as a pong*/
					n = libwebsocket_write(wsi, (char *)
						&wsi->rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING],
							wsi->rx_user_buffer_head, LWS_WRITE_PONG);
					handled = 1;
					break;

				case LWS_WS_OPCODE_07__PONG:
					/* keep the statistics... */
					wsi->pings_vs_pongs--;

					/* issue it */
					callback_action = LWS_CALLBACK_CLIENT_RECEIVE_PONG;
					break;

				case LWS_WS_OPCODE_07__CONTINUATION:
				case LWS_WS_OPCODE_07__TEXT_FRAME:
				case LWS_WS_OPCODE_07__BINARY_FRAME:
					break;

				default:

					debug("Reserved opcode 0x%2X\n", wsi->opcode);
					/*
					 * It's something special we can't understand here.
					 * Pass the payload up to the extension's parsing
					 * state machine.
					 */

					eff_buf.token = &wsi->rx_user_buffer[
								   LWS_SEND_BUFFER_PRE_PADDING];
					eff_buf.token_len = wsi->rx_user_buffer_head;

					for (n = 0; n < wsi->count_active_extensions; n++) {
						m = wsi->active_extensions[n]->callback(
							wsi->protocol->owning_server,
							wsi->active_extensions[n], wsi,
							LWS_EXT_CALLBACK_EXTENDED_PAYLOAD_RX,
								wsi->active_extensions_user[n],
										   &eff_buf, 0);
						if (m)
							handled = 1;
					}

					if (!handled) {
						fprintf(stderr, "Unhandled extended opcode "
							"0x%x - ignoring frame\n", wsi->opcode);
						wsi->rx_user_buffer_head = 0;

						return 0;
					}

					break;
				}

				/*
				 * No it's real payload, pass it up to the user callback.
				 * It's nicely buffered with the pre-padding taken care of
				 * so it can be sent straight out again using libwebsocket_write
				 */

				if (!handled && wsi->protocol->callback)
					wsi->protocol->callback(wsi->protocol->owning_server,
								wsi, (enum libwebsocket_callback_reasons) callback_action,
								wsi->user_space,
					  &wsi->rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING],
									  wsi->rx_user_buffer_head);
				wsi->rx_user_buffer_head = 0;
				break;
			default:
				fprintf(stderr, "client rx illegal state\n");
				return 1;
			}

			return 0;

		illegal_ctl_length:

			fprintf(stderr, "Control frame asking for "
						"extended length is illegal\n");
			/* kill the connection */
			return -1;

		}



		int libwebsocket_interpret_incoming_packet(struct libwebsocket *wsi,
								 unsigned char *buf, size_t len)
		{
			int n;

		#ifdef DEBUG
			fprintf(stderr, "received %d byte packet\n", (int)len);
			for (n = 0; n < len; n++)
				fprintf(stderr, "%02X ", buf[n]);
			fprintf(stderr, "\n");
		#endif

			/* let the rx protocol state machine have as much as it needs */

			n = 0;
			while (n < len)
				if (libwebsocket_rx_sm(wsi, buf[n++]) < 0)
					return -1;

			return 0;
		}


		static int
		libwebsocket_0405_frame_mask_generate(struct libwebsocket *wsi)
		{
			char buf[4 + 20];
			int n;

			/* fetch the per-frame nonce */

			n = libwebsockets_get_random(wsi->protocol->owning_server,
								wsi->frame_masking_nonce_04, 4);
			if (n != 4) {
				fprintf(stderr, "Unable to read from random device %s %d\n",
									 SYSTEM_RANDOM_FILEPATH, n);
				return 1;
			}

			/* start masking from first byte of masking key buffer */
			wsi->frame_mask_index = 0;

			if (wsi->ietf_spec_revision != 4)
				return 0;

			/* 04 only does SHA-1 more complex key */

			/*
			 * the frame key is the frame nonce (4 bytes) followed by the
			 * connection masking key, hashed by SHA1
			 */

			memcpy(buf, wsi->frame_masking_nonce_04, 4);

			memcpy(buf + 4, wsi->masking_key_04, 20);

			/* concatenate the nonce with the connection key then hash it */

			SHA1((unsigned char *)buf, 4 + 20, wsi->frame_mask_04);

			return 0;
		}

		void lws_stderr_hexdump(unsigned char *buf, size_t len)
		{
			int n;
			int m;
			int start;

			fprintf(stderr, "\n");

			for (n = 0; n < len;) {
				start = n;

				fprintf(stderr, "%04X: ", start);

				for (m = 0; m < 16 && n < len; m++)
					fprintf(stderr, "%02X ", buf[n++]);
				while (m++ < 16)
					fprintf(stderr, "   ");

				fprintf(stderr, "   ");

				for (m = 0; m < 16 && (start + m) < len; m++) {
					if (buf[start + m] >= ' ' && buf[start + m] <= 127)
						fprintf(stderr, "%c", buf[start + m]);
					else
						fprintf(stderr, ".");
				}
				while (m++ < 16)
					fprintf(stderr, " ");

				fprintf(stderr, "\n");
			}
			fprintf(stderr, "\n");
		}

		int lws_issue_raw(struct libwebsocket *wsi, unsigned char *buf, size_t len)
		{
			int n;
			int m;

			/*
			 * one of the extensions is carrying our data itself?  Like mux?
			 */

			for (n = 0; n < wsi->count_active_extensions; n++) {
				/*
				 * there can only be active extensions after handshake completed
				 * so we can rely on protocol being set already in here
				 */
				m = wsi->active_extensions[n]->callback(
						wsi->protocol->owning_server,
						wsi->active_extensions[n], wsi,
						LWS_EXT_CALLBACK_PACKET_TX_DO_SEND,
							 wsi->active_extensions_user[n], &buf, len);
				if (m < 0) {
					fprintf(stderr, "Extension reports fatal error\n");
					return -1;
				}
				if (m) /* handled */ {
		/*			fprintf(stderr, "ext sent it\n"); */
					return 0;
				}
			}

			if (!wsi->sock)
				fprintf(stderr, "** error 0 sock but expected to send\n");

			/*
			 * nope, send it on the socket directly
			 */

		#if 0
			fprintf(stderr, "  TX: ");
			lws_stderr_hexdump(buf, len);
		#endif

		#ifdef LWS_OPENSSL_SUPPORT
			if (wsi->ssl) {
				n = SSL_write(wsi->ssl, buf, len);
				if (n < 0) {
					fprintf(stderr,
						   "ERROR writing to socket\n");
					return -1;
				}
			} else {
		#endif
				n = send(wsi->sock, buf, len, MSG_NOSIGNAL);
				if (n < 0) {
					fprintf(stderr,
						   "ERROR writing to socket\n");
					return -1;
				}
		#ifdef LWS_OPENSSL_SUPPORT
			}
		#endif
			return 0;
		}

		int
		lws_issue_raw_ext_access(struct libwebsocket *wsi,
								 char *buf, size_t len)
		{
			int ret;
			struct lws_tokens eff_buf;
			int m;
			int n;

			eff_buf.token = (char *)buf;
			eff_buf.token_len = len;

			/*
			 * while we have original buf to spill ourselves, or extensions report
			 * more in their pipeline
			 */

			ret = 1;
			while (ret == 1) {

				/* default to nobody has more to spill */

				ret = 0;

				/* show every extension the new incoming data */

				for (n = 0; n < wsi->count_active_extensions; n++) {
					m = wsi->active_extensions[n]->callback(
							wsi->protocol->owning_server,
							wsi->active_extensions[n], wsi,
							LWS_EXT_CALLBACK_PACKET_TX_PRESEND,
						   wsi->active_extensions_user[n], &eff_buf, 0);
					if (m < 0) {
						fprintf(stderr, "Extension: fatal error\n");
						return -1;
					}
					if (m)
						/*
						 * at least one extension told us he has more
						 * to spill, so we will go around again after
						 */
						ret = 1;
				}

				/* assuming they left us something to send, send it */

				if (eff_buf.token_len)
					if (lws_issue_raw(wsi, (unsigned char *)eff_buf.token,
										eff_buf.token_len))
						return -1;

				/* we used up what we had */

				eff_buf.token = NULL;
				eff_buf.token_len = 0;

				/*
				 * Did that leave the pipe choked?
				 */

				if (!lws_send_pipe_choked(wsi))
					/* no we could add more */
					continue;

				debug("choked\n");

				/*
				 * Yes, he's choked.  Don't spill the rest now get a callback
				 * when he is ready to send and take care of it there
				 */
				libwebsocket_callback_on_writable(
								 wsi->protocol->owning_server, wsi);
				wsi->extension_data_pending = 1;
				ret = 0;
			}

			debug("written %d bytes to client\n", eff_buf.token_len);

			return 0;
		}

		/**
		 * libwebsocket_write() - Apply protocol then write data to client
		 * @wsi:	Websocket instance (available from user callback)
		 * @buf:	The data to send.  For data being sent on a websocket
		 *		connection (ie, not default http), this buffer MUST have
		 *		LWS_SEND_BUFFER_PRE_PADDING bytes valid BEFORE the pointer
		 *		and an additional LWS_SEND_BUFFER_POST_PADDING bytes valid
		 *		in the buffer after (buf + len).  This is so the protocol
		 *		header and trailer data can be added in-situ.
		 * @len:	Count of the data bytes in the payload starting from buf
		 * @protocol:	Use LWS_WRITE_HTTP to reply to an http connection, and one
		 *		of LWS_WRITE_BINARY or LWS_WRITE_TEXT to send appropriate
		 *		data on a websockets connection.  Remember to allow the extra
		 *		bytes before and after buf if LWS_WRITE_BINARY or LWS_WRITE_TEXT
		 *		are used.
		 *
		 *	This function provides the way to issue data back to the client
		 *	for both http and websocket protocols.
		 *
		 *	In the case of sending using websocket protocol, be sure to allocate
		 *	valid storage before and after buf as explained above.  This scheme
		 *	allows maximum efficiency of sending data and protocol in a single
		 *	packet while not burdening the user code with any protocol knowledge.
		 */

		int libwebsocket_write(struct libwebsocket *wsi, char *buf,
					  size_t len, enum libwebsocket_write_protocol protocol)
		{
			int n;
			int pre = 0;
			int post = 0;
			int shift = 7;
			int masked7 = wsi->mode == LWS_CONNMODE_WS_CLIENT &&
								  wsi->xor_mask != xor_no_mask;
			char *dropmask = NULL;
			unsigned char is_masked_bit = 0;

			if (len == 0 && protocol != LWS_WRITE_CLOSE) {
				fprintf(stderr, "zero length libwebsocket_write attempt\n");
				return 0;
			}

			if (protocol == LWS_WRITE_HTTP)
				goto send_raw;

			/* websocket protocol, either binary or text */

			if (wsi->state != WSI_STATE_ESTABLISHED)
				return -1;

			switch (wsi->ietf_spec_revision) {
			/* chrome likes this as of 30 Oct 2010 */
			/* Firefox 4.0b6 likes this as of 30 Oct 2010 */
			case 0:
				if ((protocol & 0xf) == LWS_WRITE_BINARY) {
					/* in binary mode we send 7-bit used length blocks */
					pre = 1;
					while (len & (127 << shift)) {
						pre++;
						shift += 7;
					}
					n = 0;
					shift -= 7;
					while (shift >= 0) {
						if (shift)
							buf[0 - pre + n] =
								  ((len >> shift) & 127) | 0x80;
						else
							buf[0 - pre + n] =
								  ((len >> shift) & 127);
						n++;
						shift -= 7;
					}
					break;
				}

				/* frame type = text, length-free spam mode */

				pre = 1;
				buf[-pre] = 0;
				buf[len] = 0xff; /* EOT marker */
				post = 1;
				break;

			case 7:
			case 8:
			case 13:
				if (masked7) {
					pre += 4;
					dropmask = &buf[0 - pre];
					is_masked_bit = 0x80;
				}
				/* fallthru */
			case 4:
			case 5:
			case 6:
				switch (protocol & 0xf) {
				case LWS_WRITE_TEXT:
					if (wsi->ietf_spec_revision < 7)
						n = LWS_WS_OPCODE_04__TEXT_FRAME;
					else
						n = LWS_WS_OPCODE_07__TEXT_FRAME;
					break;
				case LWS_WRITE_BINARY:
					if (wsi->ietf_spec_revision < 7)
						n = LWS_WS_OPCODE_04__BINARY_FRAME;
					else
						n = LWS_WS_OPCODE_07__BINARY_FRAME;
					break;
				case LWS_WRITE_CONTINUATION:
					if (wsi->ietf_spec_revision < 7)
						n = LWS_WS_OPCODE_04__CONTINUATION;
					else
						n = LWS_WS_OPCODE_07__CONTINUATION;
					break;

				case LWS_WRITE_CLOSE:
					if (wsi->ietf_spec_revision < 7)
						n = LWS_WS_OPCODE_04__CLOSE;
					else
						n = LWS_WS_OPCODE_07__CLOSE;

					/*
					 * v5 mandates the first byte of close packet
					 * in both client and server directions
					 */

					switch (wsi->ietf_spec_revision) {
					case 0:
					case 4:
						break;
					case 5:
						/* we can do this because we demand post-buf */

						if (len < 1)
							len = 1;

						switch (wsi->mode) {
						case LWS_CONNMODE_WS_SERVING:
							/*
							fprintf(stderr, "LWS_WRITE_CLOSE S\n");
							*/
							buf[0] = 'S';
							break;
						case LWS_CONNMODE_WS_CLIENT:
							/*
							fprintf(stderr, "LWS_WRITE_CLOSE C\n");
							*/
							buf[0] = 'C';
							break;
						default:
							break;
						}
						break;
					default:
						/*
						 * 06 has a 2-byte status code in network order
						 * we can do this because we demand post-buf
						 */

						if (wsi->close_reason) {
							/* reason codes count as data bytes */
							buf -= 2;
							buf[0] = wsi->close_reason >> 8;
							buf[1] = wsi->close_reason;
							len += 2;
						}
						break;
					}
					break;
				case LWS_WRITE_PING:
					if (wsi->ietf_spec_revision < 7)
						n = LWS_WS_OPCODE_04__PING;
					else
						n = LWS_WS_OPCODE_07__PING;

					wsi->pings_vs_pongs++;
					break;
				case LWS_WRITE_PONG:
					if (wsi->ietf_spec_revision < 7)
						n = LWS_WS_OPCODE_04__PONG;
					else
						n = LWS_WS_OPCODE_07__PONG;
					break;
				default:
					fprintf(stderr, "libwebsocket_write: unknown write "
									 "opcode / protocol\n");
					return -1;
				}

				if (!(protocol & LWS_WRITE_NO_FIN))
					n |= 1 << 7;

				if (len < 126) {
					pre += 2;
					buf[-pre] = n;
					buf[-pre + 1] = len | is_masked_bit;
				} else {
					if (len < 65536) {
						pre += 4;
						buf[-pre] = n;
						buf[-pre + 1] = 126 | is_masked_bit;
						buf[-pre + 2] = len >> 8;
						buf[-pre + 3] = len;
					} else {
						pre += 10;
						buf[-pre] = n;
						buf[-pre + 1] = 127 | is_masked_bit;
		#if defined __LP64__
							buf[-pre + 2] = (len >> 56) & 0x7f;
							buf[-pre + 3] = len >> 48;
							buf[-pre + 4] = len >> 40;
							buf[-pre + 5] = len >> 32;
		#else
							buf[-pre + 2] = 0;
							buf[-pre + 3] = 0;
							buf[-pre + 4] = 0;
							buf[-pre + 5] = 0;
		#endif
						buf[-pre + 6] = len >> 24;
						buf[-pre + 7] = len >> 16;
						buf[-pre + 8] = len >> 8;
						buf[-pre + 9] = len;
					}
				}
				break;
			}

			/*
			 * Deal with masking if we are in client -> server direction and
			 * the protocol demands it
			 */

			if (wsi->mode == LWS_CONNMODE_WS_CLIENT &&
								 wsi->ietf_spec_revision >= 4) {

				/*
				 * this is only useful for security tests where it's required
				 * to control the raw packet payload content
				 */

				if (!(protocol & LWS_WRITE_CLIENT_IGNORE_XOR_MASK) &&
								wsi->xor_mask != xor_no_mask) {

					if (libwebsocket_0405_frame_mask_generate(wsi)) {
						fprintf(stderr, "libwebsocket_write: "
								  "frame mask generation failed\n");
						return 1;
					}


					if (wsi->ietf_spec_revision < 7)
						/*
						 * use the XOR masking against everything we
						 * send past the frame key
						 */
						for (n = -pre; n < ((int)len + post); n++)
							buf[n] = wsi->xor_mask(wsi, buf[n]);
					else
						/*
						 * in v7, just mask the payload
						 */
						for (n = 0; n < (int)len; n++)
							dropmask[n + 4] =
							   wsi->xor_mask(wsi, dropmask[n + 4]);


					if (wsi->ietf_spec_revision < 7) {
						/* make space for the frame nonce in clear */
						pre += 4;

						dropmask = &buf[0 - pre];
					}

					if (dropmask)
						/* copy the frame nonce into place */
						memcpy(dropmask,
								   wsi->frame_masking_nonce_04, 4);

				} else {
					if (wsi->ietf_spec_revision < 7) {

						/* make space for the frame nonce in clear */
						pre += 4;

						buf[0 - pre] = 0;
						buf[1 - pre] = 0;
						buf[2 - pre] = 0;
						buf[3 - pre] = 0;
					} else {
						if (dropmask && wsi->xor_mask != xor_no_mask) {
							dropmask[0] = 0;
							dropmask[1] = 0;
							dropmask[2] = 0;
							dropmask[3] = 0;
						}
					}
				}

			}

		send_raw:

		#if 0
			fprintf(stderr, "send %ld: ", len + post);
			for (n = -pre; n < ((int)len + post); n++)
				fprintf(stderr, "%02X ", buf[n]);

			fprintf(stderr, "\n");
		#endif

			if (protocol == LWS_WRITE_HTTP) {
				if (lws_issue_raw(wsi, (unsigned char *)buf - pre,
										  len + pre + post))
					return -1;

				return 0;
			}

			/*
			 * give any active extensions a chance to munge the buffer
			 * before send.  We pass in a pointer to an lws_tokens struct
			 * prepared with the default buffer and content length that's in
			 * there.  Rather than rewrite the default buffer, extensions
			 * that expect to grow the buffer can adapt .token to
			 * point to their own per-connection buffer in the extension
			 * user allocation.  By default with no extensions or no
			 * extension callback handling, just the normal input buffer is
			 * used then so it is efficient.
			 *
			 * callback returns 1 in case it wants to spill more buffers
			 */

			return lws_issue_raw_ext_access(wsi, buf - pre, len + pre + post);
		}


		/**
		 * libwebsockets_serve_http_file() - Send a file back to the client using http
		 * @wsi:		Websocket instance (available from user callback)
		 * @file:		The file to issue over http
		 * @content_type:	The http content type, eg, text/html
		 *
		 *	This function is intended to be called from the callback in response
		 *	to http requests from the client.  It allows the callback to issue
		 *	local files down the http link in a single step.
		 */

		int libwebsockets_serve_http_file(struct libwebsocket *wsi, const char *file,
									   const char *content_type)
		{
			int fd;
			struct stat stat_buf;
			char buf[512];
			char *p = buf;
			int n;

		#ifdef WIN32
			fd = open(file, O_RDONLY | _O_BINARY);
		#else
			fd = open(file, O_RDONLY);
		#endif
			if (fd < 1) {
				p += sprintf(p, "HTTP/1.0 400 Bad\x0d\x0a"
					"Server: libwebsockets\x0d\x0a"
					"\x0d\x0a"
				);
				libwebsocket_write(wsi, (char *)buf, p - buf,
										LWS_WRITE_HTTP);

				return -1;
			}

			fstat(fd, &stat_buf);
			p += sprintf(p, "HTTP/1.0 200 OK\x0d\x0a"
					"Server: libwebsockets\x0d\x0a"
					"Content-Type: %s\x0d\x0a"
					"Content-Length: %u\x0d\x0a"
					"\x0d\x0a", content_type,
							(unsigned int)stat_buf.st_size);

			libwebsocket_write(wsi, (char *)buf, p - buf, LWS_WRITE_HTTP);

			n = 1;
			while (n > 0) {
				n = read(fd, buf, 512);
				if (n <= 0)
					continue;
				libwebsocket_write(wsi, (char *)buf, n,
										LWS_WRITE_HTTP);
			}

			close(fd);

			return 0;
		}


		/**
		 * libwebsockets_remaining_packet_payload() - Bytes to come before "overall"
		 *					      rx packet is complete
		 * @wsi:		Websocket instance (available from user callback)
		 *
		 *	This function is intended to be called from the callback if the
		 *  user code is interested in "complete packets" from the client.
		 *  libwebsockets just passes through payload as it comes and issues a buffer
		 *  additionally when it hits a built-in limit.  The LWS_CALLBACK_RECEIVE
		 *  callback handler can use this API to find out if the buffer it has just
		 *  been given is the last piece of a "complete packet" from the client --
		 *  when that is the case libwebsockets_remaining_packet_payload() will return
		 *  0.
		 *
		 *  Many protocols won't care becuse their packets are always small.
		 */

		size_t
		libwebsockets_remaining_packet_payload(struct libwebsocket *wsi)
		{
			return wsi->rx_packet_length;
		}
#ifdef __cplusplus
	}
#endif
